package net.cathackers.devel.scmp.auth.impl;


import net.cathackers.devel.exceptions.CATException;
import net.cathackers.devel.scmp.auth.exceptions.AuthenticationException;
import net.cathackers.devel.scmp.auth.exceptions.ProxyException;
import net.cathackers.devel.scmp.auth.exceptions.UserNotFoundException;
import net.cathackers.devel.scmp.auth.interfaces.AuthToken;
import net.cathackers.devel.scmp.auth.interfaces.AuthenticationCredentials;
import net.cathackers.devel.scmp.auth.interfaces.AuthenticationInformation;
import net.cathackers.devel.scmp.auth.interfaces.Authenticator;
import net.cathackers.devel.scmp.auth.interfaces.UserID;

import net.cathackers.devel.scmp.exceptions.BackendConnectException;
import net.cathackers.devel.scmp.exceptions.BackendException;
import net.cathackers.devel.scmp.factories.SCMPFactory;

import org.apache.log4j.Logger;
/**
 * Decorator and proxy for the real authenticator at the backend
 * @author ahmed soliman
 *
 */
public class AuthenticatorProxyImpl implements Authenticator {

    private Authenticator backend_;
    private Logger logger_;

    public AuthenticatorProxyImpl(Authenticator authBack) {
	backend_ = authBack;
	logger_ = SCMPFactory.getLogger(this);
    }

    @Override
    public AuthenticationInformation authenticate(AuthenticationCredentials authenticationCredentials) throws UserNotFoundException, ProxyException {
	
	// We don't use caching for authentication to ensure that 
	connect();
	AuthenticationInformation authInformation = null;
	try {
	    authInformation = backend_.authenticate(authenticationCredentials);
	    if (authInformation == null) {
		throw new UserNotFoundException();
	    }
	} catch (UserNotFoundException ex) {
	    logger_.error("User is not found");
	   throw new UserNotFoundException();
	} catch (CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.debug("Error while communicating with backend, authenticate(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing authenticate()");
	}
	return authInformation;
    }

    @Override
    public boolean isAuthTokenValid(AuthToken authToken) throws ProxyException {
	boolean ret = false;
	try {
	    ret = backend_.isAuthTokenValid(authToken);
	} catch (CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, isAuthTokenValid(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing isAuthTokenValid()");
	}
	return ret; 
    }

    @Override
    public void updateAuthenticationInformation(AuthToken userAuthToken, AuthenticationCredentials authenticationCredentials) throws ProxyException {
	try  {
	    backend_.updateAuthenticationInformation(userAuthToken, authenticationCredentials);
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, updateAuthenticationInformation(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing updateAuthenticationInformation()");	    
	}
    }

    @Override
    public boolean isUsernameExist(String username) throws AuthenticationException {
	try {
	    return backend_.isUsernameExist(username);
	} catch (BackendConnectException e) {
	    throw new AuthenticationException();
	}
    }

    @Override
    public void logout(AuthToken userAuthToken) throws ProxyException {
	try {
	    backend_.logout(userAuthToken);
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, logout(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing logout()");	    
	}

    }

    @Override
    public void updateAuthenticationInformation(UserID userID, AuthenticationCredentials newAuthenticationCredentials) throws ProxyException {
	try {
	    backend_.updateAuthenticationInformation(userID, newAuthenticationCredentials);
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, updateAuthenticationInformation(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing updateAuthenticationInformation()");	    
	}

    }

    @Override
    public void connect() throws ProxyException {
	try {
	    if (!backend_.isConnected()) {
		backend_.connect();
	    }
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, connect(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing connect()");	    
	}

    }

    @Override
    public void disconnect() throws ProxyException {
	try {
	    if (backend_.isConnected()) {
		backend_.disconnect();
	    }
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, disconnect(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing disconnect()");	    
	}
    }

    @Override
    public boolean isConnected() throws ProxyException {
	boolean ret = false;
	try {
	    ret = backend_.isConnected();
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, isConnected(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing isConnected()");	    
	}
	return ret;
    }

    @Override
    public void lockAccount(AuthenticationCredentials authenticationCredentials) throws ProxyException {
	try {
	    backend_.lockAccount(authenticationCredentials);
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, lockAccount(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing lockAccount()");	    
	}

    }

    @Override
    public void unlockAccount(AuthenticationCredentials authenticationCredentials) throws ProxyException {
	try {
	    backend_.unlockAccount(authenticationCredentials);
	} catch(CATException ex) {
	    // The point here is to catch any detailed exception from the backend and rewrap it into a more general exception.
	    logger_.error("Error while communicating with backend, unlockAccount(): " + ex.getMessage());
	    throw new ProxyException("Couldn't connect to the backend while doing unlockAccount()");	    
	}

    }

    @Override
    public boolean isAlive() throws AuthenticationException {
	boolean ret = false;
	try {
	    ret =  backend_.isAlive();
	} catch (BackendConnectException e) {
	    logger_.error("Error while communicating with backend");
	    throw new AuthenticationException();
	    
	} catch (BackendException e) {
	    logger_.error(e.getMessage());
	    throw new AuthenticationException();
	}
	return ret;
    }
}